﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;

public class Character : MonoBehaviour
{
    public static bool Hidden = false;
    
    //public float m;
    //public float targetSpeed1;
    //public float incDir1;
    //public float curspeed1;
    public float maxSpeed;
    public float curSpeedH;
    public float curSpeedV;
    public float mass;
    public float jumpSpeed;
    public float gravityForce;
    public float acceleration;
    public float rayOffset = 0.5f;
    public float skin = 0.005f;
    public bool isGrounded;
    public Animator animator;
    public Transform visual;
    public BoxCollider collider;
    public MoveDirection moveDir = MoveDirection.Right;
    public LayerMask mask;
    public GunScript gun;
    void Start()
    {
        animator = GetComponentInChildren<Animator>();
        collider = GetComponent<BoxCollider>();
        gun = GetComponentInChildren<GunScript>();
    }
    void Update()
    {
        //GetInput();
        Movement();
        SetAnimatorParams();
        GravityForce();

    }
    void SetAnimatorParams()
    {
        animator.SetBool("Jump", !isGrounded);
        animator.SetFloat("HorSpeed", Mathf.Abs(curSpeedH));
    }
    void GetInput()
    {
        float movementH = Input.GetAxisRaw("Horizontal");
        MoveHorizontal(movementH);
        if (Input.GetButtonDown("Jump"))
        {
            Jump();
        }
        if (Input.GetKeyDown(KeyCode.LeftControl))
        {
            Shoot();
        }
    }
    private void GravityForce()
    {
        if (isGrounded == false)
        {
            curSpeedV -= mass * gravityForce * Time.deltaTime;
        }
    }
    public void Movement()
    {
        IsGroundCollision();
        IsHorizontalCollision();
        IsRoofCollision();
        transform.Translate(new Vector2(curSpeedH * Time.deltaTime, curSpeedV * Time.deltaTime));
    }
    public void MoveHorizontal(float movement)
    {
        SetMoveDir(movement);
        float targetSpeed = movement * maxSpeed;
        float incDir = Mathf.Sign(targetSpeed - curSpeedH);
        curSpeedH += acceleration * incDir;
        curSpeedH = ((incDir == Mathf.Sign(targetSpeed - curSpeedH)) ? curSpeedH : targetSpeed);
    }
    void SetMoveDir(float movement)
    {
        if (Mathf.Abs(movement) > 0)
        {

            MoveDirection movementDir = (MoveDirection)Mathf.Sign(movement);
            if (moveDir != movementDir)
            {
                moveDir = movementDir;
                visual.Rotate(0, 180 * (float)moveDir, 0);
            }
        }
    }
    public void Jump()
    {
        if (isGrounded == true)
        {
            curSpeedV = jumpSpeed;
            SoundController.Jump();
        }
    }
    public void Shoot()
    {
        gun.Shoot(moveDir);
    }
    bool IsGroundCollision()
    {
        if (curSpeedV <= 0)
        {
            var c = collider;
            var p = transform.position;
            RaycastHit hitInfo = new RaycastHit();


            float rayDistance = Mathf.Abs(curSpeedV * Time.deltaTime) + rayOffset + skin;

            for (int i = -1; i < 2; i++)
            {
                float x = p.x + c.center.x + c.size.x / 2 * i;
                float y = p.y + c.center.y - c.size.y / 2 + rayOffset;
                Ray ray = new Ray(new Vector2(x, y), Vector3.down);
                Debug.DrawRay(ray.origin, ray.direction, Color.green);
                if (Physics.Raycast(ray, out hitInfo, Mathf.Abs(rayDistance), mask))
                {
                    float distance = Vector2.Distance(ray.origin, hitInfo.point);
                    transform.Translate(new Vector2(0, -distance + rayOffset));
                    isGrounded = true;
                    curSpeedV = 0;
                    return true;
                }
            }
        }
        isGrounded = false;

        return false;
    }
    private bool IsHorizontalCollision()
    {
        if (curSpeedH != 0)
        {
            var c = collider;
            var p = transform.position;
            RaycastHit hitInfo = new RaycastHit();
            float skin = 0.005f;
            for (int i = -1; i < 2; i++)
            {
                float x = p.x + c.center.x + c.size.x / 2 * (float)moveDir;
                float y = p.y + c.center.y + c.size.y / 2 * i;
                Ray ray = new Ray(new Vector2(x, y), new Vector2((float)moveDir, 0));
                Debug.DrawRay(ray.origin, ray.direction, Color.green);
                if (Physics.Raycast(ray, out hitInfo, Mathf.Abs(curSpeedH * Time.deltaTime), mask))
                {
                    float distance = Vector2.Distance(ray.origin, hitInfo.point);
                    transform.Translate(new Vector2((distance - skin) * (float)moveDir, 0));
                    curSpeedH = 0;
                    return true;
                }
            }
        }
        return false;
    }
    bool IsRoofCollision()
    {
        if (curSpeedV > 0)
        {
            var c = collider;
            var p = transform.position;
            RaycastHit hitInfo = new RaycastHit();
            float rayDistance = curSpeedV * Time.deltaTime + rayOffset;

            for (int i = -1; i < 2; i++)
            {
                float x = p.x + c.center.x + c.size.x / 2 * i;
                float y = p.y + c.center.y + c.size.y / 2 - rayOffset;
                Ray ray = new Ray(new Vector2(x, y), new Vector2(0, rayDistance));
                Debug.DrawRay(ray.origin, new Vector2(0, rayDistance), Color.green);
                if (Physics.Raycast(ray, out hitInfo, Mathf.Abs(rayDistance), mask))
                {

                    float distance = Vector2.Distance(ray.origin, hitInfo.point);

                    transform.Translate(new Vector2(0, +distance - rayOffset - skin));
                    curSpeedV = 0;
                    return true;
                }
            }
        }

        return false;
    }

}
